"""
系统信息扫描工具
功能：生成带彩色渐变的系统信息看板，支持ASCII艺术Logo和终端分栏布局
依赖：psutil, pillow, colorsys 等
"""

import math
import colorsys
from datetime import datetime
from typing import Dict
import GPUtil
import re
import subprocess

# 预编译正则表达式提升性能
ANSI_ESCAPE = re.compile(r'\033\[[\d;]*m')


def add_radial_gradient(text: str, start_hue: float = 0.0, end_hue: float = 0.3) -> str:
    """
    为文本添加径向渐变色（以左上角为中心）

    参数:
        text: 原始文本（可包含换行符）
        start_hue: 起始色相 (0.0-1.0)
        end_hue: 结束色相 (0.0-1.0)

    返回:
        带ANSI颜色代码的字符串

    示例:
        >>> print(add_radial_gradient("Hello\\nWorld", 0.0, 0.5))
    """
    lines = text.split('\n')
    if not lines:
        return ""

    max_y = len(lines) - 1
    max_x = max(len(line) for line in lines) - 1
    max_distance = math.sqrt(max_x ** 2 + max_y ** 2) or 1.0  # 防止除零错误

    result = []
    for y, line in enumerate(lines):
        colored_line = []
        for x, char in enumerate(line):
            # 计算归一化距离
            distance = math.sqrt(x ** 2 + y ** 2)
            ratio = min(distance / max_distance, 1.0)

            # 计算渐变色
            hue = start_hue + (end_hue - start_hue) * ratio
            r, g, b = colorsys.hsv_to_rgb(hue, 1, 1)

            # 生成ANSI代码
            ansi_code = f"\033[38;2;{int(r * 255)};{int(g * 255)};{int(b * 255)}m"
            colored_line.append(f"{ansi_code}{char}")

        result.append("".join(colored_line) + "\033[0m")

    return "\n".join(result)


class SystemInfoScanner:
    """系统信息采集与展示工具"""

    def __init__(self):
        self.ansi_escape = ANSI_ESCAPE
        self.os_info = self._get_os_info()
        self.hardware_info = self._get_hardware_info()
        self.network_info = self._get_network_info()
        self.runtime_info = self._get_runtime_info()

    def _get_os_info(self) -> Dict:
        """获取操作系统信息"""
        info = {
            'system': platform.system(),
            'release': platform.release(),
            'arch': platform.machine()
        }

        try:
            system_type = info['system']
            if system_type == 'Linux':
                self._parse_linux(info)
            elif system_type == 'Windows':
                self._parse_windows(info)
            elif system_type == 'Darwin':
                self._parse_macos(info)
        except Exception:
            info['distro'] = "Unknown"

        return info

    def _parse_linux(self, info: Dict) -> None:
        """解析Linux发行版信息"""
        with open('/etc/os-release') as f:
            for line in f:
                if line.startswith('PRETTY_NAME'):
                    info['distro'] = line.split('=', 1)[1].strip().strip('"')
                    break

    def _parse_windows(self, info: Dict) -> None:
        """解析Windows版本信息"""
        win_ver = platform.win32_ver()
        info['distro'] = f"Windows {win_ver[0]} (Build {win_ver[1]})"

    def _parse_macos(self, info: Dict) -> None:
        """解析macOS版本信息"""
        info['distro'] = f"macOS {platform.mac_ver()[0]}"

    def _get_hardware_info(self) -> Dict:
        """获取硬件信息"""
        try:
            cpu = psutil.cpu_freq()
            mem = psutil.virtual_memory()
            disk = psutil.disk_usage('/')
            gpus = GPUtil.getGPUs()
            for gpu in gpus:
                gpuName = gpu.name,
                gpuMemoryUsed = f"{gpu.memoryUsed:.1f}MB",
                gpuMemoryTotal = f"{gpu.memoryTotal:.1f}MB",
                gpuLoad = f"{gpu.load * 100:.1f}%"
                gpuTemp = f"{gpu.temperature}°C"
                break

        except Exception:
            cpu = None
            mem = disk = type('', (), {'total': 0, 'percent': 0})()

        return {
            'cpu': {
                'name': platform.processor(),
                'cores': psutil.cpu_count(logical=False) or 0,
                'threads': psutil.cpu_count() or 0,
                'max_freq': f"{cpu.max / 1000:.2f} GHz" if cpu else "N/A",
                'used': f"{psutil.cpu_percent(interval=1)}%"
            },
            'gpu': {
                'name': gpuName[0],
                'atPresence': gpuMemoryUsed[0],
                'total': gpuMemoryTotal[0],
                'used': gpuLoad,
                'Temp': gpuTemp
            },
            'memory': {
                'total': f"{mem.total // (1024 ** 3)}GB",
                'used': f"{mem.percent}%"
            },
            'disk': {
                'total': f"{disk.total // (1024 ** 3)}GB",
                'used': f"{disk.percent}%"
            }
        }

    def _get_network_info(self):
        """获取网络信息（包含IP和实时速度）"""
        # 初始化默认值
        hostname = "Unknown"
        ip = "N/A"

        try:
            # 获取基础网络信息
            hostname = socket.gethostname()
            ip = socket.gethostbyname(hostname)


        except Exception as e:
            print(f"网络信息获取失败: {str(e)}")

        # 确保所有变量都有值
        return {
            'hostname': hostname,
            'ip': ip
        }

    def get_version(self, cmd_str, versionRe):
        """获取命令内容"""
        try:
            # 执行命令并捕获标准错误输出（Java版本信息在此处）
            result = subprocess.run(
                # ["java", "-version"],
                cmd_str.split(),
                stderr=subprocess.PIPE,
                stdout=subprocess.PIPE,
                text=True,
                encoding="utf-8",
                check=True  # 若命令不存在会抛出异常
            )
        except Exception:
            return "None"

        # 从 stderr 中提取版本信息（多数 Java 实现将版本信息输出到 stderr）
        output = result.stdout or result.stderr
        version_match = re.search(versionRe, output)

        if version_match:
            return version_match.group(1)
        else:
            return "None"

    def _get_runtime_info(self) -> Dict:
        """获取运行时信息"""
        boot_time = datetime.fromtimestamp(psutil.boot_time())
        return {
            'uptime': str(datetime.now() - boot_time).split('.', 1)[0],
            'python_version': platform.python_version(),
            # 没安装环境,不实装，先注释着
            # 'java_version': self.get_version("java -version", 'version "(.*?)"'),
            # 'mysql_version': self.get_version("mysql --version", "Ver\s+(\d+\.\d+\.\d+)"),

        }

    def image_to_ascii(
            self,
            image_path: str,
            width: int = 100,
            color_mode: bool = True,
            charset: str = "@%#*+=-:. ",
            output_file: str = None
    ) -> str:
        """
        图片转ASCII艺术

        参数:
            image_path: 图片路径
            width: 输出宽度（字符数）
            color_mode: 是否启用彩色
            charset: 灰度字符集（从暗到亮）
            output_file: 输出文件路径

        异常:
            FileNotFoundError: 图片不存在时抛出
        """
        try:
            with Image.open(image_path) as img:
                # 调整尺寸并转换颜色模式
                aspect_ratio = img.height / img.width
                new_height = int(width * aspect_ratio * 0.5)
                img = img.resize((width, new_height)).convert('RGB')
                pixels = img.load()

                # 生成ASCII字符
                ascii_art = []
                for y in range(img.height):
                    line = []
                    for x in range(img.width):
                        r, g, b = pixels[x, y]

                        # 颜色代码
                        color = f"\033[38;2;{r};{g};{b}m" if color_mode else ""

                        # 灰度计算
                        gray = 0.299 * r + 0.587 * g + 0.114 * b
                        char = charset[int(gray / 255 * (len(charset) - 1))]

                        line.append(f"{color}{char}")
                    ascii_art.append("".join(line) + ("\033[0m" if color_mode else ""))

                result = "\n".join(ascii_art)

                if output_file:
                    with open(output_file, 'w') as f:
                        f.write(result)
                    return f"ASCII art saved to {output_file}"

                return result

        except FileNotFoundError:
            raise FileNotFoundError(f"图片文件不存在: {image_path}")
        except (IOError, OSError) as e:
            raise ValueError(f"图片解码失败: {str(e)}")

    def generate_ascii_logo(self) -> str:
        """生成系统Logo"""
        try:
            return '\n' + self.image_to_ascii("logo.png", width=35, color_mode=True, charset="/")
        except Exception as e:
            return f"\nLogo加载失败: {str(e)}"

    def visible_length(self, text: str) -> int:
        """计算可见文本长度（忽略ANSI代码）"""
        return len(self.ansi_escape.sub('', text))

    def display(self) -> str:
        """生成分栏布局的终端输出"""
        # 获取终端尺寸
        try:
            term_width = shutil.get_terminal_size().columns
        except AttributeError:
            term_width = 80

        # 准备左右内容
        logo = self.generate_ascii_logo().split('\n')
        info = self._generate_info_text().split('\n')
        max_lines = max(len(logo), len(info))

        # 计算布局参数
        logo_width = max(self.visible_length(ln) for ln in logo) + 4 if logo else 0
        text_width = max(term_width - logo_width - 8, 10)

        # 构建分栏输出
        output = []
        for i in range(max_lines):
            logo_line = logo[i] if i < len(logo) else ""
            info_line = info[i] if i < len(info) else ""

            logo_pad = logo_width - self.visible_length(logo_line)
            info_pad = text_width - self.visible_length(info_line)

            output.append(f"{logo_line}{' ' * logo_pad}{info_line}{' ' * info_pad}")

        return '\n'.join(output)

    def _generate_info_text(self) -> str:

        """生成带颜色渐变的系统信息"""
        sections = [
            ("系统信息", [
                f"操作系统: {self.os_info['distro']}",
                f"内核版本: {self.os_info['release']}",
                f"系统架构: {self.os_info['arch']}"
            ]),
            ("硬件信息", [
                f"CPU型号: {self.hardware_info['cpu']['name']}",
                f"⌊使用率 {self.hardware_info['cpu']['used']}",
                f"⌊核心/线程: {self.hardware_info['cpu']['cores']}核/{self.hardware_info['cpu']['threads']}线程",
                f"GPU型号: {self.hardware_info['gpu']['name']}",
                f"⌊使用率 {self.hardware_info['gpu']['used']}",
                f"⌊温度 {self.hardware_info['gpu']['Temp']}",
                f"⌊显存: {self.hardware_info['gpu']['atPresence']}/{self.hardware_info['gpu']['total']}",
                f"内存总量: {self.hardware_info['memory']['total']} (使用率 {self.hardware_info['memory']['used']})",
                f"磁盘空间: {self.hardware_info['disk']['total']} (使用率 {self.hardware_info['disk']['used']})"
            ]),
            ("网络信息", [
                f"主机名称: {self.network_info['hostname']}",
                f"IP地址: {self.network_info['ip']}",

            ]),
            ("运行状态", [
                f"运行时间: {self.runtime_info['uptime']}",
                f"Python版本: {self.runtime_info['python_version']}",
            ])
        ]

        # 构建文本块
        text_block = []
        for title, content in sections:
            text_block.append(f"[ {title} ]".center(40, '-'))
            text_block.extend(content)
            text_block.append('')

        return add_radial_gradient('\n'.join(text_block),start_hue= 0.7, end_hue = 1)


if __name__ == "__main__":
    try:
        # 依赖检查
        import platform
        import shutil
        import psutil
        import socket
        from PIL import Image

        scanner = SystemInfoScanner()
        print(scanner.display())

    except ImportError as e:
        req = {'psutil': 'psutil', 'PIL': 'pillow'}.get(e.name, e.name)
        print(f"请先安装依赖: pip install {req}")
    except Exception as e:
        print(f"运行错误: {str(e)}")
